import express from 'express'
import request from 'request'
import * as cheerio from 'cheerio'
import iconv from 'iconv-lite'
import fs from 'fs'
import path from 'path'
import * as XLSX from 'xlsx'
import {fileURLToPath} from 'url'
import ExcelJS from 'exceljs'

const router = express.Router()

// 全局进度状态
let globalProgress = {
    isProcessing: false,
    total: 0,
    finished: 0,
    success: 0,
    failed: 0,
    currentBatch: 0,
    totalBatches: 0,
    message: ''
};

/**
 * 进度查询接口
 * GET /api/progress
 */
router.get('/progress', (req, res) => {
    res.json({
        code: 200,
        data: globalProgress
    });
});

/**
 * 重置进度状态
 */
function resetProgress() {
    globalProgress = {
        isProcessing: false,
        total: 0,
        finished: 0,
        success: 0,
        failed: 0,
        currentBatch: 0,
        totalBatches: 0,
        message: ''
    };
}

/**
 * 更新进度状态
 */
function updateProgress(progress) {
    Object.assign(globalProgress, progress);
}

// 性能优化配置
const CONFIG = {
    BATCH_SIZE: 10,              // 每批处理数量
    DELAY_BETWEEN_BATCHES: 5000, // 批次间延迟(ms)
    DELAY_BETWEEN_REQUESTS: 2000, // 请求间延迟(ms)
    MAX_RETRIES: 3,              // 最大重试次数
    TIMEOUT: 30000,              // 请求超时时间(ms)
    MAX_CONCURRENT: 5            // 最大并发数
}

/**
 * 通用 GET 请求方法（带重试机制）
 */
export function requestGet(url, params, callback, retryCount = 0) {
    let fullUrl = url
    if (params && typeof params === 'object') {
        const query = Object.entries(params)
            .map(([key, val]) => `${encodeURIComponent(key)}=${encodeURIComponent(val)}`)
            .join('&')
        fullUrl += (url.includes('?') ? '&' : '?') + query
    }
    
    const requestOptions = {
        url: fullUrl,
        encoding: null,
        gzip: true,
        timeout: CONFIG.TIMEOUT
    }
    
    request.get(requestOptions, function (error, response, body) {
        if (error && retryCount < CONFIG.MAX_RETRIES) {
            console.log(`请求失败，${CONFIG.DELAY_BETWEEN_REQUESTS/1000}秒后重试 (${retryCount + 1}/${CONFIG.MAX_RETRIES}): ${url}`)
            setTimeout(() => {
                requestGet(url, params, callback, retryCount + 1)
            }, CONFIG.DELAY_BETWEEN_REQUESTS)
            return
        }
        
        // 默认用 utf-8 解码
        let html = body ? body.toString('utf-8') : ''
        // 检查 meta 标签或响应头
        const charsetMatch = html.match(/<meta.*?charset=["']?([\w-]+)["']?/i) ||
            (response && response.headers['content-type'] && response.headers['content-type'].match(/charset=([\w-]+)/i));
        let charset = charsetMatch ? charsetMatch[1].toLowerCase() : 'utf-8'
        if (charset !== 'utf-8' && charset !== 'utf8') {
            try {
                html = iconv.decode(body, charset)
            } catch (e) {
                // fallback
                html = iconv.decode(body, 'gbk')
            }
        }
        callback(error, response, html)
    })
}


/**
 * 批量运行接口
 * POST /api/batchRun
 * body: [{ 视频链接: 'https://www.bilibili.com/video/BV1j4MvzcEnx', ... }, ...]
 */
router.post('/batchRun', async (req, res) => {
    const data = req.body[0]
    const filePath = data.path
    
    // 立即返回任务ID，开始异步处理
    const taskId = Date.now().toString();
    
    res.json({
        code: 200,
        message: '任务已开始',
        taskId: taskId
    });
    
    // 异步处理数据
    processBilibiliData(filePath, taskId);
});

/**
 * 异步处理B站数据
 */
async function processBilibiliData(filePath, taskId) {
    try {
        // 重置进度状态
        resetProgress();
        updateProgress({
            isProcessing: true,
            message: '开始读取文件...'
        });
        
        // 1. 用 fs 读取文件为 Buffer
        const fileBuffer = fs.readFileSync(filePath)

        // 2. 用 xlsx 解析 Buffer
        const workbook = XLSX.read(fileBuffer, {type: 'buffer'})

        // 3. 获取第一个 sheet
        const sheetName = workbook.SheetNames[0]
        const sheet = workbook.Sheets[sheetName]

        // 4. 转为 JSON
        const jsonData = XLSX.utils.sheet_to_json(sheet, {defval: ''})

        console.log(`开始处理 ${jsonData.length} 条B站数据，任务ID: ${taskId}`);
        
        const result = await getBilibiliVideoInfo(jsonData, taskId);
        
        // 处理完成
        updateProgress({
            isProcessing: false,
            message: `处理完成！成功: ${result.success}, 失败: ${result.failed}，文件路径为：${result.message}`,
            finished: result.total,
            success: result.success,
            failed: result.failed
        });
        
    } catch (error) {
        console.error('处理失败:', error);
        updateProgress({
            isProcessing: false,
            message: `处理失败: ${error.message}`
        });
    }
}

export default router

function formatTimestamp(ts) {
    const date = new Date(ts * 1000); // 时间戳单位是秒，需乘1000
    const y = date.getFullYear();
    const m = String(date.getMonth() + 1).padStart(2, '0');
    const d = String(date.getDate()).padStart(2, '0');
    const h = String(date.getHours()).padStart(2, '0');
    const min = String(date.getMinutes()).padStart(2, '0');
    const s = String(date.getSeconds()).padStart(2, '0');
    return `${y}-${m}-${d} ${h}:${min}:${s}`;
}

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

async function getBilibiliVideoInfo(jsonData, taskId) {
    const result = []
    const errorList = []
    const total = jsonData.length;
    let finished = 0;
    
    console.log(`开始处理 ${total} 条B站数据，分批大小: ${CONFIG.BATCH_SIZE}`);

    // 更新初始进度
    updateProgress({
        total: total,
        finished: 0,
        success: 0,
        failed: 0,
        currentBatch: 0,
        totalBatches: Math.ceil(total / CONFIG.BATCH_SIZE),
        message: '开始处理数据...'
    });

    // 分批处理
    for (let batchStart = 0; batchStart < total; batchStart += CONFIG.BATCH_SIZE) {
        const batchEnd = Math.min(batchStart + CONFIG.BATCH_SIZE, total);
        const currentBatch = jsonData.slice(batchStart, batchEnd);
        const currentBatchNum = Math.floor(batchStart/CONFIG.BATCH_SIZE) + 1;
        
        console.log(`处理批次 ${currentBatchNum}/${Math.ceil(total/CONFIG.BATCH_SIZE)} (${batchStart + 1}-${batchEnd})`);
        
        // 更新批次进度
        updateProgress({
            currentBatch: currentBatchNum,
            message: `处理批次 ${currentBatchNum}/${Math.ceil(total/CONFIG.BATCH_SIZE)}`
        });
        
        // 处理当前批次
        const batchPromises = currentBatch.map(async (item, batchIndex) => {
            const idx = batchStart + batchIndex;
            const url = item.视频链接;
            const prefix = "https://www.bilibili.com/video/";
            const bvid = url.startsWith(prefix) ? url.slice(prefix.length) : url;
            const httpUrl = 'https://api.bilibili.com/x/web-interface/view?bvid=' + bvid;
            
            return new Promise(resolve => {
                requestGet(httpUrl, null, (error, response, body) => {
                    let video = null;
                    let isError = false;
                    
                    if (error) {
                        isError = true;
                        console.log(`请求失败 (${idx + 1}/${total}): ${url}`);
                    } else {
                        try {
                            const data = JSON.parse(body);
                            
                            if (data.code === 0 && data.data) {
                                //视频标题
                                const title = data.data.title;
                                //作者
                                const author = data.data.owner.name;
                                // 播放量
                                const playCount = data.data.stat.view;
                                //点赞
                                const like = data.data.stat.like;
                                //投币
                                const coin = data.data.stat.coin;
                                //收藏
                                const collect = data.data.stat.favorite;
                                //转发
                                const share = data.data.stat.share;
                                //评论
                                const reply = data.data.stat.reply;
                                //发布时间
                                const pubdate = formatTimestamp(data.data.pubdate);
                                
                                video = {
                                    title,
                                    author,
                                    playCount,
                                    like,
                                    coin,
                                    collect,
                                    share,
                                    reply,
                                    pubdate,
                                    url
                                };
                                
                                console.log(`✅ 成功处理 (${idx + 1}/${total}): ${video.title}`);
                            } else {
                                console.log(`❌ API返回错误 (${idx + 1}/${total}): ${data.message || '未知错误'}`);
                                isError = true;
                            }
                            
                            // 检查字段完整性
                            if (video) {
                                for (const key in video) {
                                    if (video[key] === undefined || video[key] === null || video[key] === '') {
                                        isError = true;
                                        break;
                                    }
                                }
                            }
                        } catch (e) {
                            console.log(`❌ 解析失败 (${idx + 1}/${total}): ${e.message}`);
                            isError = true;
                        }
                    }
                    
                    if (isError) {
                        errorList.push(idx);
                        // 填充空数据，保证Excel行数一致
                        video = {
                            title: '解析失败',
                            author: '解析失败',
                            playCount: 0,
                            like: 0,
                            coin: 0,
                            collect: 0,
                            share: 0,
                            reply: 0,
                            pubdate: '解析失败',
                            url: url
                        };
                    }
                    
                    result[idx] = video;
                    finished++;
                    
                    // 实时更新进度
                    const progress = Math.round((finished / total) * 100);
                    updateProgress({
                        finished: finished,
                        success: finished - errorList.length,
                        failed: errorList.length,
                        message: `进度: ${progress}% (${finished}/${total})`
                    });
                    
                    console.log(`进度: ${progress}% (${finished}/${total})`);
                    
                    resolve();
                });
            });
        });
        
        // 等待当前批次完成
        await Promise.all(batchPromises);
        
        // 批次间延迟（最后一批不需要延迟）
        if (batchEnd < total) {
            console.log(`批次完成，等待 ${CONFIG.DELAY_BETWEEN_BATCHES/1000} 秒后继续...`);
            updateProgress({
                message: `批次完成，等待 ${CONFIG.DELAY_BETWEEN_BATCHES/1000} 秒后继续...`
            });
            await sleep(CONFIG.DELAY_BETWEEN_BATCHES);
        }
    }

    console.log(`✅ 所有B站数据处理完成！成功: ${result.length - errorList.length}, 失败: ${errorList.length}`);

    // 保存结果
    updateProgress({
        message: '正在保存结果文件...'
    });
    
    const workbook = new ExcelJS.Workbook();
    const worksheet = workbook.addWorksheet('Sheet1');

    // 表头
    const header = ['标题', '作者', '播放量', '点赞', '投币', '收藏', '转发', '评论', '发布时间', '视频链接'];
    worksheet.addRow(header);

    // 数据
    result.forEach((row, idx) => {
        const rowData = [
            row.title, row.author, row.playCount, row.like, row.coin,
            row.collect, row.share, row.reply, row.pubdate, row.url
        ];
        const excelRow = worksheet.addRow(rowData);
        // 如果是异常行，设置背景色
        if (errorList.includes(idx)) {
            excelRow.eachCell(cell => {
                cell.fill = {
                    type: 'pattern',
                    pattern: 'solid',
                    fgColor: {argb: 'FFFFFF00'} // 黄色
                };
            });
        }
    });

    // 确保 uploads/result 目录存在
    const uploadDir = path.resolve(process.cwd(), 'uploads/result')
    if (!fs.existsSync(uploadDir)) {
        fs.mkdirSync(uploadDir, {recursive: true});
    }

    const date = new Date();
    const timestamp = date.toISOString().replace(/[:.]/g, '-').slice(0, 19);
    const savePath = path.join(uploadDir, `${timestamp}_bilibili_result.xlsx`);
    await workbook.xlsx.writeFile(savePath);
    console.log('✅ 已保存到 ' + savePath);
    
    return {
        code: 200,
        message: "文件路径为" + savePath,
        total: total,
        success: result.length - errorList.length,
        failed: errorList.length,
        progress: 100
    }
}
